import classNames from 'classnames';
import PropTypes from 'prop-types';
import React, { ReactNode } from 'react';
import { ITree, treeMap } from '../../utils/utility';
import { Icon } from '../icon';
import { Text } from '../text';

export interface ITreeItemProps {
  expanded: boolean;
  checked: boolean;
  title: string;
  onExpandedToggle?: React.MouseEventHandler<Element>;
  onCheckedToggle?: React.MouseEventHandler<Element>;
  checkable?: boolean;
  hasChildren?: boolean;
  className?: string;
  disabled?: boolean;
  halfChecked?: boolean;
}

const TREE_NODE_HEIGHT = 28;

const TreeItem = (props: ITreeItemProps) => (
  <div className={props.className}>
    {props.hasChildren ? (
      <Icon
        onClick={props.onExpandedToggle}
        type={props.expanded ? 'subtract-case' : 'add-case'}
        style={{ marginRight: '4px' }}
        color="#b8b8b8"
      />
    ) : null}
    {props.checkable ? (
      props.halfChecked && !props.checked ? (
        <svg
          viewBox="0 0 14 14"
          width="16"
          height="16"
          className={`br-tree-node__halfChecked ${props.disabled ? 'disabled' : ''}`}
          onClick={props.onCheckedToggle}
        >
          <rect x="0" y="0" width="14" height="14" fill="none" strokeWidth="1" stroke="#888888" />
          <rect x="3" y="3" width="8" height="8" fill="#e22e33" />
        </svg>
      ) : (
        <Icon
          className={`br-tree-node__checkboxIcon ${props.disabled ? 'disabled' : ''}`}
          onClick={props.onCheckedToggle}
          type={props.checked ? 'selected' : 'unselected'}
          style={{ marginRight: '4px' }}
          color={props.checked ? '#e22e33' : '#b8b8b8'}
        />
      )
    ) : null}
    <Text className="br-tree-node__title" color={props.disabled ? '#a8a8a8' : ''} ellipsis title={props.title}>
      {props.title}
    </Text>
  </div>
);

export interface ITreeNodeProps {
  defaultTree?: ITree;
  treeNode: ITree;
  style?: React.CSSProperties;
  className?: string;
  onChange?: (tree: ITree) => void;
}

export interface ISingleTreeState {
  tree: ITree;
}

export class TreeNode extends React.Component<ITreeNodeProps, ISingleTreeState> {
  public static TREE_NODE_HEIGHT = TREE_NODE_HEIGHT;

  public static propTypes = {
    style: PropTypes.object,
    className: PropTypes.string,
    treeNode: PropTypes.shape({
      key: PropTypes.string.isRequired,
      title: PropTypes.string.isRequired,
      children: PropTypes.array,
    }),
    onChange: PropTypes.func,
  };

  public static isLeaf(node: ITree) {
    return !(node.children && node.children.length);
  }

  /** 初始状态渲染 */
  public static correctCheckedState(tree: ITree): ITree {
    if (TreeNode.isLeaf(tree)) {
      return tree;
    }
    const children = (tree.children as ITree[]).map((subTree) => TreeNode.correctCheckedState(subTree));
    const allChildChecked = children.every((subTree) => !!subTree.checked || (!subTree.checked && !!subTree.disabled));
    const hasChildChecked = children.some((subTree) => !!subTree.checked);
    const hasChildUnchecked = children.some((subTree) => !subTree.halfChecked);
    const hasHalfChecked = children.some((subTree) => !!subTree.halfChecked);
    const allChildDisabled = children.every((subTree) => !!subTree.disabled);
    const halfChecked = hasHalfChecked || (hasChildChecked && hasChildUnchecked);

    return {
      ...tree,
      checked: allChildChecked,
      halfChecked,
      children,
      disabled: allChildDisabled,
    };
  }

  // 如果传入了外部props，更新到state
  public static getDerivedStateFromProps(nextProps: ITreeNodeProps) {
    return nextProps.treeNode ? { tree: TreeNode.correctCheckedState(nextProps.treeNode) } : null;
  }

  constructor(props: ITreeNodeProps) {
    super(props);
    this.renderNode = this.renderNode.bind(this);
    this.state = { tree: this.props.defaultTree || { key: 'default', title: '没有数据' } };
  }

  public renderNode(treeNode: ITree, onChange?: (treeNode: ITree) => void) {
    const hasChildren = treeNode.children && treeNode.children.length;
    let children: ReactNode[] = [];

    /**
     * 处理选中
     */
    const handleCheckedToggle = () => {
      if (!treeNode.disabled) {
        if (onChange) {
          const checked = !treeNode.checked;
          const deepTreeNode = (curNode: ITree, checkStatus: boolean) => {
            let { children: curChildren = [] } = curNode;
            curChildren = curChildren.map((item: ITree) => {
              return deepTreeNode(item, checkStatus);
            });
            return {
              ...curNode,
              checked: curNode.disabled ? curNode.checked : checkStatus,
              children: curChildren,
            };
          };
          const checkState = treeNode.disabled ? treeNode.checked : checked;
          const tempNode = {
            ...treeNode,
            checked: !!checkState,
          };
          onChange(
            treeMap(tempNode as ITree, (node: ITree) => deepTreeNode(node, checked)),
          );
        }
      }
    };

    /**
     * 处理展开
     */
    const handleExpandedToggle = () => {
      if (onChange) {
        onChange({ ...treeNode, expanded: !treeNode.expanded });
      }
    };

    /**
     * 子节点与父节点相互作用
     */
    if (treeNode.expanded && treeNode.children) {
      // 子节点控制父节点
      children = treeNode.children.map((node, index) => {
        // 展开时，引用parent，减少遍历操作

        return this.renderNode({ ...node }, (newNode: ITree) => {
          if (onChange) {
            const newChildren = [
              ...(treeNode.children || []).slice(0, index),
              newNode,
              ...(treeNode.children || []).slice(index + 1),
            ];
            const parentChecked = newChildren.every((childNode) => !!childNode.checked);
            const childAllNoChecked = newChildren.every((childNode) => !childNode.checked);
            onChange({
              ...treeNode,
              checked: parentChecked,
              halfChecked: !parentChecked && !childAllNoChecked,
              children: newChildren,
            });
          }
        });
      });
      // }
    }

    const props: ITreeItemProps = {
      title: treeNode.title,
      expanded: !!(hasChildren && treeNode.expanded),
      checked: !!treeNode.checked,
      hasChildren: !!hasChildren,
      checkable: true, // 暂时全部为true
      onCheckedToggle: handleCheckedToggle,
      onExpandedToggle: handleExpandedToggle,
      disabled: !!treeNode.disabled,
      halfChecked: !!treeNode.halfChecked,
    };

    return (
      <li key={treeNode.key} className={classNames('br-tree-node', this.props.className)}>
        <TreeItem
          {...props}
          className={classNames('br-tree-node__item', { 'br-tree-node__item--leaf': TreeNode.isLeaf(treeNode) })}
        />
        <ul className="br-tree-node__children">{children}</ul>
      </li>
    );
  }

  public render() {
    return this.renderNode(this.state.tree, (node) => this.props.onChange && this.props.onChange(node));
  }
}
